home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / et / et-2_2.lha / et2.2 / src / StyledText.C < prev    next >
C/C++ Source or Header  |  1990-12-07  |  19KB  |  891 lines

  1. //$StyledText,StyledTextIter,Style,StyleTable,TextRunArray$
  2.  
  3. #include "StyledText.h"
  4. #include "RunArray.h"
  5. #include "Mark.h"
  6. #include "Port.h"
  7. #include "Error.h"
  8. #include "ObjectTable.h"
  9.  
  10. //------ StyleSpec ------------------------------------------------------
  11.  
  12. StyleSpec::StyleSpec()
  13.     font= eFontChicago; 
  14.     face= eFacePlain; 
  15.     size= 12; 
  16.     ink= ePatBlack; 
  17.     xor= TRUE; 
  18. }
  19.     
  20. StyleSpec::StyleSpec(Font *fp, GrPattern c, bool mode)
  21.     font= fp->Fid(); 
  22.     face= fp->Face(); 
  23.     size= fp->Size(); 
  24.     ink= c; 
  25.     xor= mode; 
  26. }
  27.  
  28. StyleSpec::StyleSpec(GrFont ft, GrFace fc, int sz, GrPattern c, bool mode)
  29.     font= ft; 
  30.     face= fc; 
  31.     size= sz; 
  32.     ink= c; 
  33.     xor= mode; 
  34. }
  35.  
  36. //------ StyleTable ------------------------------------------------------
  37.  
  38. class StyleTable: public OrdCollection {
  39. public:
  40.     MetaDef(StyleTable);
  41.     StyleTable() : OrdCollection(cCollectionInitCap)
  42.     { ObjectTable::AddRoot(this); }
  43.     Style *MakeStyle(GrFont ft, GrFace fc, int size, GrPattern ink);
  44.     Style *MakeStyle(Style *);
  45. };
  46.  
  47. static StyleTable *Styles;
  48.  
  49. MetaImpl0(StyleTable); 
  50.  
  51. Style *StyleTable::MakeStyle(GrFont ft, GrFace fc, int size, GrPattern ink)
  52. {
  53.     Iter next(this);
  54.     register Style *sp;
  55.     while (sp= (Style*)next()) {
  56.     register Font *f= sp->fp;
  57.     if (f->Fid() == ft && f->Size() == size && f->Face() == fc &&
  58.         sp->ink == ink) 
  59.         return sp;
  60.     }
  61.     sp= new_Style(0, new_Font(ft, size, fc), ink);
  62.     Add(sp);
  63.     return sp;
  64. }
  65.  
  66. Style *StyleTable::MakeStyle(Style *asp)
  67. {
  68.     Iter next(this);
  69.     Style *sp;
  70.     while (sp= (Style*)next()) 
  71.     if (sp->IsEqual(asp))
  72.         return sp;
  73.     Add(asp);
  74.     return asp;
  75. }
  76.  
  77. //------ Style -----------------------------------------------------------
  78.  
  79. MetaImpl(Style, (TP(fp), TP(ink), 0)); 
  80.  
  81. Style::Style(int, FontPtr f, GrPattern c)
  82. {
  83.     fp= f;  
  84.     ink= c;  
  85. }
  86.  
  87. Style *new_Style(int i, FontPtr f, GrPattern c)
  88. {
  89.     return new Style(i, f, c);
  90. }
  91.  
  92. Style *new_Style(FontPtr f, GrPattern c)
  93. {
  94.     if (Styles == 0)
  95.     Styles= new StyleTable;
  96.     return Styles->MakeStyle(f->Fid(), f->Face(), f->Size(), c);
  97. }
  98.  
  99. Style *new_Style(GrFont ft, GrFace fc, int size, GrPattern ink)
  100. {
  101.     if (Styles == 0)
  102.     Styles= new StyleTable;
  103.     return Styles->MakeStyle(ft, fc, size, ink);
  104. }
  105.  
  106. Style::~Style()
  107.     this= 0;
  108. }
  109.  
  110. ostream &Style::PrintOn(ostream &s) 
  111. {    
  112.     return s << fp SP << ink SP;
  113. }
  114.  
  115. istream &Style::ReadFrom(istream &s) 
  116.     char c;
  117.     
  118.     s >> fp;
  119.     s.eatwhite();
  120.     s.get(c);
  121.     s.putback(c);
  122.     if (c != '}')       // new Style with ink
  123.     s >> ink;
  124.     else                // old Style without ink
  125.     ink= ePatBlack;
  126.     return s;
  127. }
  128.  
  129. ostream &Style::DisplayOn(ostream &s) 
  130. {
  131.     return s << fp->AsString() NL;
  132. }
  133.  
  134. bool Style::IsEqual(Object* op)
  135. {
  136.     if (!op->IsKindOf(Style))
  137.     return FALSE;
  138.  
  139.     Style *sp= (Style*)op;
  140.     register Font *f= sp->fp;
  141.     return (f->Fid() == fp->Fid() && 
  142.         f->Size() == fp->Size() && 
  143.         f->Face() == fp->Face() &&
  144.         ink == sp->ink);
  145. }
  146.  
  147. void Style::GetStyle(GrFont *fid, GrFace *face, int *size, GrPattern *col)
  148. {
  149.     *fid= fp->Fid();
  150.     *face= fp->Face();
  151.     *size= fp->Size();
  152.     *col= ink;
  153. }
  154.  
  155. ObjPtr Style::DeepClone()
  156. {
  157.     return this;
  158. }
  159.  
  160. //---- class TextRunArray --------------------------------------------------
  161.  
  162. MetaImpl(TextRunArray, (TP(st), 0)); 
  163.  
  164. TextRunArray::TextRunArray(StyledText *sp, int elements) : RunArray(elements)
  165. {
  166.     st= sp;
  167. }
  168.  
  169. ObjPtr TextRunArray::RunAt(int i, int *start, int *end, int *size ,int *lenat)
  170. {
  171.     // requests for styles beyond the end of the text receive the
  172.     // same style information as at the end of the text
  173.     int at= i;
  174.     i= min(i, Size()-1);
  175.     if (i < 0) { // take styleHere into account
  176.     *start= *end= at;
  177.     *size= *lenat= 0;
  178.     return (ObjPtr)st->GetCurrentStyle();
  179.     }
  180.     return RunArray::RunAt(i, start, end, size, lenat);
  181. }
  182.  
  183. ostream &TextRunArray::PrintOn(ostream &s) 
  184. {
  185.     RunArray::PrintOn(s);
  186.     return s << st SP;
  187. }
  188.  
  189. istream &TextRunArray::ReadFrom(istream &s) 
  190.     RunArray::ReadFrom(s);
  191.     return s >> st;
  192. }
  193.  
  194. Object *TextRunArray::ReadItem(istream& s)
  195. {
  196.     Style *sp;
  197.     s >> sp;
  198.     if (Styles == 0)
  199.     Styles= new StyleTable;
  200.     sp= Styles->MakeStyle(sp);
  201.     return sp;    
  202. }
  203.  
  204. //----- class StyledTextIter ---------------------------------------------
  205.  
  206. StyledTextIter::StyledTextIter(Text *s, int from, int to) 
  207.                               : GapTextIter(s, from, to)
  208. {
  209.     if (!s->IsKindOf(StyledText))
  210.     Error("StyledTextIter::StyledTextIter", "StyledText expected (%s received)",
  211.                                 s->ClassName());
  212.     nextFontChange= ce;
  213.     NextFontChange();
  214.     if (sp == 0) {
  215.     sp= new_Style(gSysFont);
  216.     Error("StyledTextIter::StyledTextIter", "style is nil");
  217.     }
  218. }
  219.  
  220. void StyledTextIter::Reset(Text *s, int from, int to)
  221.     if (!s->IsKindOf(StyledText))
  222.     Error("StyledTextIter::Reset", "StyledText expected (%s received)",
  223.                                 s->ClassName());
  224.     GapTextIter::Reset(s,from,to);
  225.     nextFontChange= ce;
  226.     NextFontChange();
  227.     if (sp == 0) {
  228.     sp= new_Style(gSysFont);
  229.     Error("StyledTextIter::Reset", "style is nil");
  230.     }
  231. }
  232.  
  233. int StyledTextIter::operator()()  
  234. {
  235.     return GapTextIter::operator()();
  236. }
  237.  
  238. int StyledTextIter::Line(LineDesc *ld)
  239. {
  240.     register StyledText *pt = (StyledText*)ct;
  241.     unget = ce;
  242.     NextFontChange();
  243.     if (ld) 
  244.     ld->FromFont(sp->GetStyle());
  245.  
  246.     if (ce == upto) { // special case if last line is empty
  247.     int last = pt->CharAt(ce-1);
  248.     ce++;
  249.     if (last == '\n' || last == '\r')
  250.         return upto;
  251.     }
  252.     if (ce > upto)
  253.     return cEOT;
  254.  
  255.     while (ce < upto) {
  256.     int ch = pt->CharAt(ce);
  257.     if (NextFontChange() && ld)
  258.         ld->Max(sp->GetStyle());
  259.     if (DoEscape(ce,ch)) 
  260.         pt->CalcEscape(ce,ld);
  261.     ce++;
  262.     if (ch == '\n' || ch == '\r')
  263.         break;
  264.     }
  265.     return ce;
  266. }
  267.  
  268. int StyledTextIter::operator()(int *w, LineDesc *ld)  
  269. {
  270.     register StyledText *pt = (StyledText*)ct;
  271.  
  272.     *w = 0;
  273.     if (ce == upto )
  274.     return cEOT;
  275.  
  276.     NextFontChange();
  277.     int ch = CharAt(ce);
  278.     if (DoEscape(ce,ch))
  279.     *w = pt->CalcEscape(ce,ld);
  280.     else {      
  281.     *w = sp->GetStyle()->Width(ch);
  282.     if (ld)
  283.         ld->FromFont(sp->GetStyle());
  284.     }
  285.     ce++;
  286.     return ch;
  287. }
  288.  
  289. int StyledTextIter::Token(int *w,LineDesc *ld)  
  290. {
  291.     register StyledText *pt = (StyledText*)ct;
  292.  
  293.     unget= ce;
  294.     *w = 0;
  295.     NextFontChange();
  296.     if (ld) 
  297.     ld->FromFont(sp->GetStyle());
  298.     if (ce >= upto)
  299.     return cEOT;
  300.     register int ch= CharAt(ce);
  301.     if (Isspace(ch)) {
  302.     *w = sp->GetStyle()->Width(ch);
  303.     ce++;
  304.     return (ch);
  305.     } else if (DoEscape(ce,ch)) {
  306.     *w = pt->CalcEscape(ce,ld);
  307.     ce++;
  308.     return (ch);
  309.     }
  310.     while (ce < upto && !Isspace(CharAt(ce)) && !DoEscape(ce,CharAt(ce))) {
  311.     if (NextFontChange() && ld)
  312.         ld->Max(sp->GetStyle());
  313.     ch = CharAt(ce++);
  314.     *w += sp->GetStyle()->Width(ch);
  315.     }
  316.     return (ch);
  317. }
  318.  
  319. bool StyledTextIter::NextFontChange ()
  320.     if (ce == nextFontChange) {
  321.     sp = (Style*)  ((StyledText*)ct)->styles->RunAt(ce,&start,&end,&size,&lenat);
  322.     nextFontChange = ce + lenat;
  323.     return TRUE;
  324.     }
  325.     else
  326.     return FALSE;
  327. }
  328.  
  329. //----- class StyledText --------------------------------------------------
  330.  
  331. MetaImpl(StyledText, (TP(styles), TP(sp), TP(styleHere), T(applyStyleHere),
  332.     /* T(escape), */ T(nextFontChange), T(start), T(end), 
  333.     T(size), T(lenat), 0));    
  334.  
  335. static TextChanges changeRec;
  336.  
  337. StyledText::StyledText()
  338. {
  339.     styles= new TextRunArray(this);
  340.     Init(gSysFont, TRUE);
  341. }
  342.  
  343. StyledText::StyledText(int size, FontPtr fd) : GapText(size, fd)
  344. {
  345.     styles= new TextRunArray(this);
  346.     Init(fd, TRUE);
  347. }
  348.  
  349. StyledText::StyledText(byte *buf, int len, bool ic, FontPtr fd)  
  350.                              : GapText(buf, len, ic, fd)
  351. {
  352.     styles= new TextRunArray(this);
  353.  
  354.     if (Size()) {
  355.     styles->Insert(new_Style(fd), 0, 0, Size());
  356.     Init(gSysFont, FALSE);
  357.     } else 
  358.     Init(fd, TRUE);
  359. }
  360.  
  361. StyledText::StyledText(TextRunArray *st, byte *buf, int len, bool ic)
  362.                             : GapText(buf, len, ic)
  363. {
  364.     if (st->Size() != Size())
  365.     Error("StyledText", "StyleArray does not correspond to the text");
  366.     styles= st;
  367.     Init(gSysFont, FALSE);
  368. }
  369.  
  370. StyledText::StyledText(FontPtr fd, char* va_(fmt), ...)
  371. {
  372.     Style *st= new_Style(fd);
  373.     char *buf;
  374.  
  375.     va_list ap;
  376.     va_start(ap,va_(fmt));
  377.     buf= strvprintf(va_(fmt), ap);
  378.     va_end(ap);
  379.     BuildStylesFromString(st, buf);
  380.     Init(fd, FALSE);
  381.     SafeDelete(buf);
  382. }
  383.  
  384. StyledText::~StyledText()
  385. {
  386.     SafeDelete(styles);
  387.     SafeDelete(styleHere);
  388. }
  389.  
  390. void StyledText::InitNew()
  391. {
  392.     GapText::InitNew();
  393.     styles= new TextRunArray(this);
  394.     Init(gSysFont, TRUE);
  395. }
  396.  
  397. void StyledText::Init(FontPtr fd, bool nullStyle)
  398. {
  399.     styleHere= new_Style(fd);
  400.     if (nullStyle)
  401.     applyStyleHere= nullStyle;
  402.     escape= '0';
  403. }
  404.  
  405. void StyledText::ReplaceWithStr(byte *str,int len)
  406. {
  407.     GapText::ReplaceWithStr(str, len);
  408.     SafeDelete(styles);
  409.     Init(GetFont(), FALSE);   
  410. }
  411.  
  412. void StyledText::Cut(int from,int to)
  413. {
  414.     int start, end, size, lenat;
  415.     DoDelayChanges dc(this);
  416.     // if we delete a complete run |xxxx|XXXXXXX
  417.     //                             ^         ^ we will set styleHere
  418.  
  419.     Style *sp= (Style*)styles->RunAt(from,&start,&end,&size,&lenat);
  420.     applyStyleHere = FALSE;
  421.     if (start == from && size <= to - from) {
  422.     applyStyleHere = TRUE;
  423.     styleHere = sp;
  424.     }
  425.     GapText::Cut(from,to);
  426.     styles->Cut(from,to,FALSE);
  427. }
  428.  
  429. void StyledText::Paste(Text* t,int from,int to)
  430. {
  431.     DoDelayChanges dc(this);
  432.     GapText::Paste(t,from,to);
  433.     if (t->IsKindOf(StyledText)) { 
  434.     StyledText *st = (StyledText *)t;
  435.     if (styles)
  436.         styles->Paste(st->styles, from, to, FALSE);
  437.     else
  438.         Error("Paste", "styles == 0");
  439.     }  else {
  440.     int start, end, size, lenat;
  441.     if (from != to) {
  442.         Style *sp= (Style*)styles->RunAt(from, &start, &end, &size, &lenat);
  443.         if (start == from && size <= to - from) {
  444.         applyStyleHere= TRUE;
  445.         styleHere= sp;
  446.         }
  447.         styles->Cut(from,to,FALSE);
  448.     }
  449.     if (applyStyleHere && t->Size()) { // insert new run with styleHere
  450.         //styles->Insert (new_Style(styleHere->GetStyle()), from, from, t->Size());
  451.         styles->Insert (styleHere,from ,from , t->Size());
  452.         applyStyleHere= FALSE;
  453.     }
  454.     else 
  455.         styles->ChangeRunSize(from, t->Size());
  456.     }       
  457. }
  458.  
  459. void StyledText::Copy(Text* save,int from, int to)
  460. {
  461.     if (!CheckRange(Size(),from,to) || save == 0)
  462.     return;
  463.     GapText::Copy(save,from,to);
  464.  
  465.     if (!save->IsKindOf(StyledText)) 
  466.     return;
  467.  
  468.     StyledText *st = (StyledText *)save;
  469.     if (applyStyleHere && Size() == 0) {
  470.     st->applyStyleHere = TRUE;
  471.     st->styleHere = styleHere;
  472.     } else 
  473.     styles->Copy(st->styles,from,to);
  474. }
  475.  
  476. TextPtr StyledText::Save(int from, int to)
  477. {
  478.     if (!CheckRange(Size(),from,to))
  479.     return 0;
  480.  
  481.     StyledText* t= new StyledText(to-from);
  482.     Copy(t, from, to);
  483.     return t;
  484. }
  485.  
  486. void StyledText::SetFStringVL(char *fmt, va_list ap)
  487. {
  488.     char *buf= strvprintf(fmt, ap);
  489.     FontPtr fd= GetFont();
  490.     Empty();
  491.     Style *st= GetStyle(0);
  492.     BuildStylesFromString(st, buf);
  493.     SafeDelete(buf);
  494.     Init(fd, FALSE);
  495. }
  496.  
  497. void StyledText::Insert(byte c, int from,int to)
  498. {
  499.     DoDelayChanges dc(this);
  500.     GapText::Insert(c,from,to);
  501.     if (applyStyleHere)  { // insert new run with styleHere 
  502.     styles->Insert(new_Style(styleHere->GetStyle()), from, from, 1);
  503.     applyStyleHere= FALSE;
  504.     } else 
  505.     styles->ChangeRunSize(from,1);
  506. }
  507.  
  508. Text *StyledText::GetScratchText(int size)
  509. {
  510.     return new GapText(size);
  511. }
  512.  
  513. void StyledText::DrawText(int from, int to, Rectangle clip)
  514. {
  515.     if (!CheckRange(Size(), from ,to))
  516.     return;
  517.     int ch;
  518.     nextFontChange= from;
  519.     NextFontChange(from);
  520.     GrSetFont(sp->GetStyle());
  521.     GrSetTextPattern(sp->GetInk());
  522.  
  523.     Point start= GrGetTextPos();
  524.     for (int i= from; i < to; i++) {
  525.     if (NextFontChange(i)) {
  526.         GrSetFont(sp->GetStyle());
  527.         GrSetTextPattern(sp->GetInk());
  528.     }
  529.     if ((ch= CharAt(i)) == '\t') 
  530.         GrTextAdvance(Tabulate(GrGetTextPos().x-start.x)); 
  531.     else if (DoEscape(i,ch)) {
  532.         DrawEscape(i,clip);
  533.         NextFontChange(nextFontChange = i); // reload current style
  534.         GrSetFont(sp->GetStyle());
  535.         GrSetTextPattern(sp->GetInk());
  536.     } else
  537.         GrDrawChar(ch);
  538.     }
  539. }
  540.  
  541. void StyledText::DrawTextJust (int from, int to, int w, Point start, Rectangle r)
  542. {
  543.     register byte ch;
  544.     int ntab, longBlanks, addSpace, seenTabs;
  545.  
  546.     if (!CheckRange(Size(), from, to))
  547.     return;
  548.  
  549.     ntab= longBlanks= seenTabs = 0;
  550.  
  551.     CalcIws(w, from, &to, &addSpace, &longBlanks, &ntab);    
  552.     GrTextMoveto(start);
  553.     NextFontChange(nextFontChange= from);
  554.     GrSetFont(sp->GetStyle());
  555.     GrSetTextPattern(sp->GetInk());
  556.     for (int i = from, nBlanks = 0; i < to; i++) {
  557.     if (NextFontChange(i)) {
  558.         GrSetFont(sp->GetStyle());
  559.         GrSetTextPattern(sp->GetInk());
  560.     }
  561.     switch (ch = CharAt(i)) {
  562.     case '\t':
  563.         GrTextAdvance(Tabulate(GrGetTextPos().x-start.x));
  564.         seenTabs++;
  565.         break;
  566.     case ' ':
  567.         GrTextAdvance(sp->GetStyle()->Width(' '));
  568.         if (seenTabs == ntab) {
  569.         GrTextAdvance(addSpace);
  570.         if (nBlanks < longBlanks)
  571.             GrTextAdvance(1);
  572.         nBlanks++;
  573.         }
  574.         break;
  575.     default:
  576.         if (DoEscape(i,ch)) {
  577.         DrawEscape(i,r);
  578.         NextFontChange(nextFontChange = i); // reload current style
  579.         GrSetFont(sp->GetStyle());
  580.         GrSetTextPattern(sp->GetInk());
  581.         }
  582.         else
  583.         GrDrawChar (CharAt(i));
  584.     }
  585.     }
  586. }
  587.  
  588. void StyledText::JustifiedMap(int from, int to, int w, int stopAt, int posX, 
  589.                                int *charPos, int *x)
  590. {
  591.     register byte ch;
  592.     int ntab, longBlanks, addSpace, seenTabs, cx, wx;
  593.  
  594.     if (!CheckRange(Size(), from, to))
  595.     return;
  596.  
  597.     wx= cx= ntab= longBlanks= addSpace= seenTabs= 0;
  598.  
  599.     CalcIws(w, from, &to, &addSpace, &longBlanks, &ntab);    
  600.     nextFontChange = from;
  601.  
  602.     for (int i = from, nBlanks = 0; i < to && i < stopAt; i++) {
  603.     NextFontChange(i); 
  604.     switch (ch = CharAt(i)) {
  605.     case '\t':
  606.         wx = Tabulate(cx);
  607.         seenTabs++;
  608.         break;
  609.     case ' ':
  610.         wx= sp->GetStyle()->Width(' ');
  611.         if (seenTabs == ntab) {
  612.         wx += addSpace;
  613.         if (nBlanks < longBlanks)
  614.             wx++; 
  615.         nBlanks++;
  616.         }
  617.         break;
  618.     default:
  619.         if (DoEscape(i,ch)) 
  620.         wx = CalcEscape(i);
  621.         else 
  622.         wx = sp->GetStyle()->Width(ch); 
  623.         break;
  624.     }
  625.     if (cx + (wx/2) > posX)
  626.         break;
  627.     cx += wx;
  628.     }
  629.     if (x)
  630.     *x = cx;
  631.     if (charPos)
  632.     *charPos= i;
  633. }
  634.  
  635. int StyledText::TextWidth(int from, int to)
  636. {
  637.     if (!CheckRange(Size(), from ,to))
  638.     return 0;
  639.  
  640.     int w= 0, ch;
  641.  
  642.     nextFontChange= from;
  643.     NextFontChange(from);
  644.  
  645.     for (int i= from; i < to; i++) {
  646.     NextFontChange(i);
  647.     ch= CharAt(i);
  648.     if (ch == '\t') 
  649.         w+= Tabulate(w); 
  650.     else {
  651.         if (DoEscape(i,ch))
  652.         w+= CalcEscape(i);
  653.         else 
  654.         w+= sp->GetStyle()->Width (ch);
  655.     }
  656.     }
  657.     return w;
  658. }
  659.  
  660. TextIter *StyledText::MakeIterator(int from, int to)
  661.     return new StyledTextIter(this, from, to); 
  662. }
  663.  
  664. ostream &StyledText::PrintOn(ostream &s) 
  665. {
  666.     GapText::PrintOn(s);
  667.     return s << styles SP << (int)escape SP;
  668. }
  669.  
  670. istream &StyledText::ReadFrom(istream &s) 
  671. {
  672.     int esc;
  673.  
  674.     GapText::ReadFrom(s);
  675.     s >> styles >> esc;
  676.     escape= esc;
  677.     applyStyleHere= (Size() == 0);
  678.     return s;
  679. }
  680.  
  681. istream& StyledText::ReadFromAsPureText(istream &s, long sizeHint)
  682. {
  683.     GapText::ReadFromAsPureText(s, sizeHint);
  684.     applyStyleHere= (Size() == 0);
  685.     styleHere= new_Style(GapText::GetFont(0));
  686.     styles->Insert(new_Style(GapText::GetFont(0)), 0, 0, Size());
  687.     return s;
  688. }
  689.  
  690. void StyledText::SetStyle(StChangeStyle mode, int from, int to, StyleSpec st)
  691. {
  692.     int start, end, size;
  693.  
  694.     if (from == to) {
  695.     Style *sp= applyStyleHere ? styleHere : GetStyle(max(0, from-1));
  696.     applyStyleHere= TRUE;
  697.     styleHere= ApplySpec(sp, st, mode);
  698.     } else {
  699.     Style **spp;
  700.     RunArray newStyles(2); 
  701.     styles->Copy(&newStyles, from, to);
  702.     RunArrayIter next(&newStyles);
  703.     while (spp= (Style**)next.RunPtr(&start, &end, &size)) 
  704.         *spp= ApplySpec(*spp, st, mode);
  705.     styles->Paste(&newStyles, from, to, FALSE);
  706.     GetMarkList()->RangeChanged(from, to - from);
  707.     Send(cIdNone, eTextChangedRange, changeRec(from, to));     
  708.     }
  709. }
  710.   
  711. Style *StyledText::ApplySpec(Style *ostyle, StyleSpec st, StChangeStyle mode)
  712. {
  713.     GrFont fid;
  714.     GrFace face;
  715.     int    fsize;
  716.     GrPattern fink;
  717.     
  718.     ostyle->GetStyle (&fid, &face, &fsize, &fink);
  719.     if ((mode & eStFont) == eStFont)
  720.     fid= st.font;
  721.     if ((mode & eStFace) == eStFace)
  722.     if (st.face == eFacePlain)
  723.         face= st.face;
  724.     else {
  725.         if (st.xor)
  726.         face= (GrFace)(face ^ st.face);
  727.         else
  728.         face= (GrFace)(face | st.face);
  729.     }
  730.     if ((mode & eStSize) == eStSize)
  731.     fsize= st.size;
  732.     if ((mode & eStAddSize) == eStAddSize)
  733.     fsize+= st.size;
  734.     if ((mode & eStInk) == eStInk)
  735.     fink= st.ink;
  736.     if (Styles == 0)
  737.     Styles= new StyleTable;
  738.     return Styles->MakeStyle(fid, face, fsize, fink);
  739. }
  740.  
  741. void StyledText::BuildStylesFromString(Style *st, char *buf)
  742. {
  743.     GrFace face= eFacePlain;
  744.     GrFont fid; 
  745.     int run= 0, size;
  746.     GrPattern ink;
  747.     char *p;
  748.  
  749.     styles = new TextRunArray(this);
  750.     for (p= buf; *p; *p++) {
  751.     if (*p == '@') {
  752.         if (*(p+1) && index("OUSBIP",*(p+1))) {
  753.            if (run) {
  754.            st->GetStyle(&fid, &face, &size, &ink);
  755.            int sz= styles->Size();
  756.            styles->Insert(st->DeepClone(), sz, sz, run);
  757.            run = 0;
  758.         }
  759.         p++;
  760.         switch (*p) {
  761.         case 'P':
  762.             face= eFacePlain;
  763.             break;
  764.         case 'O':
  765.             face= (GrFace) (face ^ eFaceOutline);
  766.             break;
  767.         case 'S':
  768.             face= (GrFace) (face ^ eFaceShadow);
  769.             break;
  770.         case 'U':
  771.             face= (GrFace) (face ^ eFaceUnderline);
  772.             break;
  773.         case 'B':
  774.             face= (GrFace) (face ^ eFaceBold);
  775.             break;
  776.         case 'I':
  777.             face= (GrFace) (face ^ eFaceItalic);
  778.             break;
  779.         }
  780.         st= new_Style(fid, face, size);
  781.          } else { 
  782.          p++;
  783.          if (!*p)
  784.              break;
  785.          GapText::Insert(*p, Size(), Size());
  786.          run++;
  787.          }
  788.     } else {
  789.         GapText::Insert(*p, Size(), Size());
  790.         run++;
  791.     }
  792.     }
  793.     if (run) {
  794.     int sz= styles->Size();
  795.     styles->Insert(st->DeepClone(), sz, sz, run);
  796.     }
  797. }
  798.  
  799. Style *StyledText::GetStyle(int at)
  800. {
  801.     int dummy;
  802.     return (Style*) styles->RunAt(at, &dummy, &dummy, &dummy, &dummy);
  803. }
  804.  
  805. void StyledText::SetFont(FontPtr fp)
  806. {
  807.     SetStyle(eStAll, 0, Size(), StyleSpec(fp));
  808. }
  809.  
  810. FontPtr StyledText::GetFont(int at)
  811. {
  812.     Style *st = GetStyle(at);
  813.     if (st)
  814.     return st->GetStyle();
  815.     else
  816.     return GapText::GetFont(at);
  817. }
  818.  
  819. void StyledText::ReplaceStyles(RunArray *st, int from, int to)
  820. {
  821.     if (to-from != st->Size())
  822.     Error("ReplaceStyle", "RunArray does not match text");
  823.     styles->Paste(st,from,to,FALSE);
  824.     GetMarkList()->RangeChanged(from,to - from);
  825.     Send(cIdNone, eTextChangedRange, changeRec(from, to));     
  826. }
  827.  
  828. void StyledText::CopyStyles(RunArray *st,int from, int to)
  829. {
  830.     styles->Copy(st,from,to);
  831. }
  832.  
  833. void StyledText::ResetCurrentStyle()
  834. {
  835.     if (Size())
  836.     applyStyleHere = FALSE;
  837. }
  838.  
  839. const Style *StyledText::GetCurrentStyle()
  840. {
  841.     if (applyStyleHere)
  842.     return styleHere;
  843.     return 0;    
  844. }
  845.  
  846. TextRunArray *StyledText::GetStyles()
  847. {
  848.     return styles; 
  849. }
  850.  
  851. TextRunArray *StyledText::SetStyles(TextRunArray *st)
  852. {
  853.     TextRunArray *old = styles;
  854.     styles = st;
  855.     return old;
  856. }
  857.  
  858. void StyledText::SetEscapeChar(byte ch)
  859. {
  860.     escape = ch;
  861. }
  862.  
  863. byte StyledText::GetEscapeChar()
  864. {
  865.     return escape;
  866. }
  867.  
  868. int StyledText::CalcEscape (int, LineDesc*)
  869. {
  870.     return 0;
  871. }
  872.  
  873. void StyledText::DrawEscape (int,Rectangle)
  874. {
  875. }
  876.  
  877. bool StyledText::IsEscape (int)
  878. {
  879.     return FALSE;
  880. }
  881.  
  882.